#ifndef BASE_INCLUDE_FILE_ARCHIVE_H
#define BASE_INCLUDE_FILE_ARCHIVE_H

#include "conf.h"
#include "misc.h"
#include "typedefs.h"
//---------------------------------------------------------
// Serialize
//---------------------------------------------------------
namespace base
{
	class archive_error:public std::logic_error
	{
	public:
		archive_error(const char * msg = "bad archive" )
			: logic_error(msg)
		{}

		archive_error(const archive_error& rhs)
			: logic_error(rhs)
		{}

		virtual ~archive_error()
		{}
	};

	// class oarchive
	class oarchive
	{
	public:
		typedef const uint8_t * Mark;
	public:
		oarchive(buffer& buf):m_buffer(buf), m_pointer(buf.begin()) {}
	public:
		bool write(bool val)
		{
			if (capacity() >= sizeof(val))
			{
				*((bool*)m_pointer) = val;
				m_pointer += sizeof(val);
				return true;
			}
			return false;
		}

		bool write(char val)
		{
			if (capacity() >= sizeof(val))
			{
				*((char*)m_pointer) = val;
				m_pointer += sizeof(val);
				return true;
			}
			return false;
		}

		bool write(int8_t val)
		{
			if (capacity() >= sizeof(val))
			{
				*((int8_t*)m_pointer) = val;
				m_pointer += sizeof(val);
				return true;
			}
			return false;
		}

		bool write(int16_t val)
		{
			if (capacity() >= sizeof(val))
			{
				*((int16_t*)m_pointer) = SwapEndian(val);
				m_pointer += sizeof(val);
				return true;
			}
			return false;
		}

		bool write(int32_t val)
		{
			if (capacity() >= sizeof(val))
			{
				*((int32_t*)m_pointer) = SwapEndian(val);
				m_pointer += sizeof(val);
				return true;
			}
			return false;
		}

		bool write(int64_t val)
		{
			if (capacity() >= sizeof(val))
			{
				*((int64_t*)m_pointer) = SwapEndian(val);
				m_pointer += sizeof(val);
				return true;
			}
			return false;
		}
	
		bool write(uint8_t val)
		{
			if (capacity() >= sizeof(val))
			{
				*((uint8_t*)m_pointer) = val;
				m_pointer += sizeof(val);
				return true;
			}
			return false;
		}

		bool write(uint16_t val)
		{
			if (capacity() >= sizeof(val))
			{
				*((uint16_t*)m_pointer) = SwapEndian(val);
				m_pointer += sizeof(val);
				return true;
			}
			return false;
		}

		bool write(uint32_t val)
		{
			if (capacity() >= sizeof(val))
			{
				*((uint32_t*)m_pointer) = SwapEndian(val);
				m_pointer += sizeof(val);
				return true;
			}
			return false;
		}

		bool write(uint64_t val)
		{
			if (capacity() >= sizeof(val))
			{
				*((uint64_t*)m_pointer) = SwapEndian(val);
				m_pointer += sizeof(val);
				return true;
			}
			return false;
		}

		bool write(float32_t val)
		{
			if (capacity() >= sizeof(val))
			{
				*((float32_t*)m_pointer) = val;
				m_pointer += sizeof(val);
				return true;
			}
			return false;
		}

		bool write(float64_t val)
		{
			if (capacity() >= sizeof(val))
			{
				*((float64_t*)m_pointer) = val;
				m_pointer += sizeof(val);
				return true;
			}
			return false;
		}
	
		bool write(const void * p, size_t len)
		{
			if (capacity() >= len)
			{
				memcpy(m_pointer, p, len);
				m_pointer += len;
				return true;
			}
			return false;
		}

		bool write_array(const bool * buf, size_t count)
		{
			assert(buf != NULL);
			size_t len = sizeof(bool) * count;
			if (capacity() >= len)
			{
				memcpy(m_pointer, buf, len);
				m_pointer += len;
				return true;
			}
			return false;
		}

		bool write_array(const char * buf, size_t count)
		{
			assert(buf != NULL);
			size_t len = sizeof(char) * count;
			if (capacity() >= len)
			{
				memcpy(m_pointer, buf, len);
				m_pointer += len;
				return true;
			}
			return false;
		}

		bool write_array(const int8_t * buf, size_t count)
		{
			assert(buf != NULL);
			size_t len = sizeof(int8_t) * count;
			if (capacity() >= len)
			{
				memcpy(m_pointer, buf, len);
				m_pointer += len;
				return true;
			}
			return false;
		}

		bool write_array(const int16_t * buf, size_t count)
		{
			assert(buf != NULL);
			size_t len = sizeof(int16_t) * count;
			if (capacity() >= len)
			{
#if defined(BIG_ENDIAN)
				int16_t * p = (int16_t*)m_pointer;
				for (size_t i = 0; i < count; i++)
				{
					p[i] = SwapEndian(buf[i]);
				}
#else
				memcpy(m_pointer, buf, len);
#endif
				m_pointer += len;
				return true;
			}
			return false;
		}

		bool write_array(const int32_t * buf, size_t count)
		{
			assert(buf != NULL);
			size_t len = sizeof(int32_t) * count;
			if (capacity() >= len)
			{
#if defined(BIG_ENDIAN)
				int32_t * p = (int32_t*)m_pointer;
				for (size_t i = 0; i < count; i++)
				{
					p[i] = SwapEndian(buf[i]);
				}
#else
				memcpy(m_pointer, buf, len);
#endif
				m_pointer += len;
				return true;
			}
			return false;
		}

		bool write_array(const int64_t * buf, size_t count)
		{
			assert(buf != NULL);
			size_t len = sizeof(int64_t) * count;
			if (capacity() >= len)
			{
#if defined(BIG_ENDIAN)
				int64_t * p = (int64_t*)m_pointer;
				for (size_t i = 0; i < count; i++)
				{
					p[i] = SwapEndian(buf[i]);
				}
#else
				memcpy(m_pointer, buf, len);
#endif
				m_pointer += len;
				return true;
			}
			return false;
		}

		bool write_array(const uint8_t * buf, size_t count)
		{
			assert(buf != NULL);
			size_t len = sizeof(uint8_t) * count;
			if (capacity() >= len)
			{
				memcpy(m_pointer, buf, len);
				m_pointer += len;
				return true;
			}
			return false;
		}

		bool write_array(const uint16_t * buf, size_t count)
		{
			assert(buf != NULL);
			size_t len = sizeof(uint16_t) * count;
			if (capacity() >= len)
			{
#if defined(BIG_ENDIAN)
				uint16_t * p = (uint16_t*)m_pointer;
				for (size_t i = 0; i < count; i++)
				{
					p[i] = SwapEndian(buf[i]);
				}
#else
				memcpy(m_pointer, buf, len);
#endif
				m_pointer += len;
				return true;
			}
			return false;
		}

		bool write_array(const uint32_t * buf, size_t count)
		{
			assert(buf != NULL);
			size_t len = sizeof(uint32_t) * count;
			if (capacity() >= len)
			{
#if defined(BIG_ENDIAN)
				uint32_t * p = (uint32_t*)m_pointer;
				for (size_t i = 0; i < count; i++)
				{
					p[i] = SwapEndian(buf[i]);
				}
#else
				memcpy(m_pointer, buf, len);
#endif
				m_pointer += len;
				return true;
			}
			return false;
		}

		bool write_array(const uint64_t * buf, size_t count)
		{
			assert(buf != NULL);
			size_t len = sizeof(uint64_t) * count;
			if (capacity() >= len)
			{
#if defined(BIG_ENDIAN)
				uint64_t * p = (uint64_t*)m_pointer;
				for (size_t i = 0; i < count; i++)
				{
					p[i] = SwapEndian(buf[i]);
				}
#else
				memcpy(m_pointer, buf, len);
#endif
				m_pointer += len;
				return true;
			}
			return false;
		}

		bool write_array(const float32_t * buf, size_t count)
		{
			assert(buf != NULL);
			size_t len = sizeof(float32_t) * count;
			if (capacity() >= len)
			{
				memcpy(m_pointer, buf, len);
				m_pointer += len;
				return true;
			}
			return false;
		}

		bool write_array(const float64_t * buf, size_t count)
		{
			assert(buf != NULL);
			size_t len = sizeof(float64_t) * count;
			if (capacity() >= len)
			{
				memcpy(m_pointer, buf, len);
				m_pointer += len;
				return true;
			}
			return false;
		}

		template <typename T>
		bool write_array(T * buf, size_t count)
		{
			try {
				for (size_t i = 0; i < count; i++)
				{
					(*this)&buf[i];
				}
			} catch(...)
			{
				throw archive_error();
			}
			return true;
		}

	public:
		bool write_count_tag(size_t count)
		{
			return write(int32_t(count));
		}
	public:
		Mark mark() const { return m_pointer; }
		void revert(const Mark& m) { assert(m >= m_buffer.begin()); assert(m <= m_buffer.end()); m_pointer = const_cast<uint8_t*>(m); }
		uint8_t * data() { return m_buffer.begin(); }
		const uint8_t * data() const { return m_buffer.begin(); }
		size_t size() const { return m_pointer - m_buffer.begin(); }
		size_t capacity() const { return m_buffer.end() - m_pointer; }
		void clear() { m_pointer = m_buffer.begin(); }
	private:
		buffer		m_buffer;
		uint8_t *	m_pointer;
	};


	// class iarchive
	class iarchive
	{
	public:
		typedef const uint8_t * Mark;
	public:
		iarchive(const buffer& buf):m_buffer(buf), m_pointer(buf.begin()) {}
	public:
		bool check(bool & val) const
		{
			if (size() >= sizeof(val))
			{
				val = *((bool*)m_pointer);
				return true;
			}
			return false;
		}

		bool check(char & val) const
		{
			if (size() >= sizeof(val))
			{
				val = *((char*)m_pointer);
				return true;
			}
			return false;
		}

		bool check(int8_t & val) const
		{
			if (size() >= sizeof(val))
			{
				val = *((int8_t*)m_pointer);
				return true;
			}
			return false;
		}

		bool check(int16_t & val) const
		{
			if (size() >= sizeof(val))
			{
				val = SwapEndian(*((int16_t*)m_pointer));
				return true;
			}
			return false;
		}

		bool check(int32_t & val) const
		{
			if (size() >= sizeof(val))
			{
				val = SwapEndian(*((int32_t*)m_pointer));
				return true;
			}
			return false;
		}

		bool check(int64_t & val) const
		{
			if (size() >= sizeof(val))
			{
				val = SwapEndian(*((int64_t*)m_pointer));
				return true;
			}
			return false;
		}

		bool check(uint8_t & val) const
		{
			if (size() >= sizeof(val))
			{
				val = *((uint8_t*)m_pointer);
				return true;
			}
			return false;
		}

		bool check(uint16_t & val) const
		{
			if (size() >= sizeof(val))
			{
				val = SwapEndian(*((uint16_t*)m_pointer));
				return true;
			}
			return false;
		}

		bool check(uint32_t & val) const
		{
			if (size() >= sizeof(val))
			{
				val = SwapEndian(*((uint32_t*)m_pointer));
				return true;
			}
			return false;
		}

		bool check(uint64_t & val) const
		{
			if (size() >= sizeof(val))
			{
				val = SwapEndian(*((uint64_t*)m_pointer));
				return true;
			}
			return false;
		}

		bool check(float32_t & val) const
		{
			if (size() >= sizeof(val))
			{
				val = (*((float32_t*)m_pointer));
				return true;
			}
			return false;
		}

		bool check(float64_t & val) const
		{
			if (size() >= sizeof(val))
			{
				val = (*((float64_t*)m_pointer));
				return true;
			}
			return false;
		}

		bool check(void * buf, size_t len) const
		{
			assert(buf);
			if (size() >= len)
			{
				memcpy(buf, m_pointer, len);
				return true;
			}
			return false;
		}

		bool read(bool & val)
		{
			if (check(val))
			{
				m_pointer += sizeof(val);
				return true;
			}
			return false;
		}

		bool read(char & val)
		{
			if (check(val))
			{
				m_pointer += sizeof(val);
				return true;
			}
			return false;
		}

		bool read(int8_t & val)
		{
			if (check(val))
			{
				m_pointer += sizeof(val);
				return true;
			}
			return false;
		}

		bool read(int16_t & val)
		{
			if (check(val))
			{
				m_pointer += sizeof(val);
				return true;
			}
			return false;
		}

		bool read(int32_t & val)
		{
			if (check(val))
			{
				m_pointer += sizeof(val);
				return true;
			}
			return false;
		}

		bool read(int64_t & val)
		{
			if (check(val))
			{
				m_pointer += sizeof(val);
				return true;
			}
			return false;
		}

		bool read(uint8_t & val)
		{
			if (check(val))
			{
				m_pointer += sizeof(val);
				return true;
			}
			return false;
		}

		bool read(uint16_t & val)
		{
			if (check(val))
			{
				m_pointer += sizeof(val);
				return true;
			}
			return false;
		}

		bool read(uint32_t & val)
		{
			if (check(val))
			{
				m_pointer += sizeof(val);
				return true;
			}
			return false;
		}

		bool read(uint64_t & val)
		{
			if (check(val))
			{
				m_pointer += sizeof(val);
				return true;
			}
			return false;
		}

		bool read(float32_t & val)
		{
			if (check(val))
			{
				m_pointer += sizeof(val);
				return true;
			}
			return false;
		}

		bool read(float64_t & val)
		{
			if (check(val))
			{
				m_pointer += sizeof(val);
				return true;
			}
			return false;
		}

		bool read(void * buf, size_t len)
		{
			if (check(buf, len))
			{
				m_pointer += len;
				return true;
			}
			return false;
		}

		bool read_array(bool * buf, size_t count)
		{
			assert(buf != NULL);
			if (count == 0)
			{
				return true;
			}
			size_t len = sizeof(bool) * count;
			if (size() >= len)
			{
				memcpy(buf, m_pointer, len);
				m_pointer += len;
				return true;
			}
			return false;
		}

		bool read_array(char * buf, size_t count)
		{
			assert(buf != NULL);
			if (count == 0)
			{
				return true;
			}
			size_t len = sizeof(char) * count;
			if (size() >= len)
			{
				memcpy(buf, m_pointer, len);
				m_pointer += len;
				return true;
			}
			return false;
		}

		bool read_array(int8_t * buf, size_t count)
		{
			assert(buf != NULL);
			if (count == 0)
			{
				return true;
			}
			size_t len = sizeof(int8_t) * count;
			if (size() >= len)
			{
				memcpy(buf, m_pointer, len);
				m_pointer += len;
				return true;
			}
			return false;
		}

		bool read_array(int16_t * buf, size_t count)
		{
			assert(buf != NULL);
			if (count == 0)
			{
				return true;
			}
			size_t len = sizeof(int16_t) * count;
			if (size() >= len)
			{
#if defined(BIG_ENDIAN)
				int16_t * p = (int16_t*)m_pointer;
				for (size_t i = 0; i < count; i++)
				{
					buf[i] = SwapEndian(p[i]);
				}
#else
				memcpy(buf, m_pointer, len);
#endif
				m_pointer += len;
				return true;
			}
			return false;
		}

		bool read_array(int32_t * buf, size_t count)
		{
			assert(buf != NULL);
			if (count == 0)
			{
				return true;
			}
			size_t len = sizeof(int32_t) * count;
			if (size() >= len)
			{
#if defined(BIG_ENDIAN)
				int32_t * p = (int32_t*)m_pointer;
				for (size_t i = 0; i < count; i++)
				{
					buf[i] = SwapEndian(p[i]);
				}
#else
				memcpy(buf, m_pointer, len);
#endif
				m_pointer += len;
				return true;
			}
			return false;
		}

		bool read_array(int64_t * buf, size_t count)
		{
			assert(buf != NULL);
			if (count == 0)
			{
				return true;
			}
			size_t len = sizeof(int64_t) * count;
			if (size() >= len)
			{
#if defined(BIG_ENDIAN)
				int64_t * p = (int64_t*)m_pointer;
				for (size_t i = 0; i < count; i++)
				{
					buf[i] = SwapEndian(p[i]);
				}
#else
				memcpy(buf, m_pointer, len);
#endif
				m_pointer += len;
				return true;
			}
			return false;
		}

		bool read_array(uint8_t * buf, size_t count)
		{
			assert(buf != NULL);
			if (count == 0)
			{
				return true;
			}
			size_t len = sizeof(uint8_t) * count;
			if (size() >= len)
			{
				memcpy(buf, m_pointer, len);
				m_pointer += len;
				return true;
			}
			return false;
		}

		bool read_array(uint16_t * buf, size_t count)
		{
			assert(buf != NULL);
			if (count == 0)
			{
				return true;
			}
			size_t len = sizeof(uint16_t) * count;
			if (size() >= len)
			{
#if defined(BIG_ENDIAN)
				uint16_t * p = (uint16_t*)m_pointer;
				for (size_t i = 0; i < count; i++)
				{
					buf[i] = SwapEndian(p[i]);
				}
#else
				memcpy(buf, m_pointer, len);
#endif
				m_pointer += len;
				return true;
			}
			return false;
		}

		bool read_array(uint32_t * buf, size_t count)
		{
			assert(buf != NULL);
			if (count == 0)
			{
				return true;
			}
			size_t len = sizeof(uint32_t) * count;
			if (size() >= len)
			{
#if defined(BIG_ENDIAN)
				uint32_t * p = (uint32_t*)m_pointer;
				for (size_t i = 0; i < count; i++)
				{
					buf[i] = SwapEndian(p[i]);
				}
#else
				memcpy(buf, m_pointer, len);
#endif
				m_pointer += len;
				return true;
			}
			return false;
		}

		bool read_array(uint64_t * buf, size_t count)
		{
			assert(buf != NULL);
			if (count == 0)
			{
				return true;
			}
			size_t len = sizeof(uint64_t) * count;
			if (size() >= len)
			{
#if defined(BIG_ENDIAN)
				uint64_t * p = (uint64_t*)m_pointer;
				for (size_t i = 0; i < count; i++)
				{
					buf[i] = SwapEndian(p[i]);
				}
#else
				memcpy(buf, m_pointer, len);
#endif
				m_pointer += len;
				return true;
			}
			return false;
		}

		bool read_array(float32_t * buf, size_t count)
		{
			assert(buf != NULL);
			if (count == 0)
			{
				return true;
			}
			size_t len = sizeof(float32_t) * count;
			if (size() >= len)
			{
				memcpy(buf, m_pointer, len);
				m_pointer += len;
				return true;
			}
			return false;
		}

		bool read_array(float64_t * buf, size_t count)
		{
			assert(buf != NULL);
			if (count == 0)
			{
				return true;
			}
			size_t len = sizeof(float64_t) * count;
			if (size() >= len)
			{
				memcpy(buf, m_pointer, len);
				m_pointer += len;
				return true;
			}
			return false;
		}

		template <typename T>
		bool read_array(T * buf, size_t count)
		{
			try {
				for (size_t i = 0; i < count; i++)
				{
					(*this)&buf[i];
				}
			} catch(...)
			{
				throw archive_error();
			}
			return true;
		}

	public:
		bool read_count_tag(size_t& count)
		{
			int32_t tag = 0;
			if (read(tag))
			{
				count = tag;
				return true;
			}
			count = 0;
			return false;
		}
	public:
		Mark mark() const { return m_pointer; }
		void revert(const Mark& m) { assert(m >= m_buffer.begin()); assert(m <= m_buffer.end()); m_pointer = m; }
		bool skip(size_t n) { if (size() >= n) { m_pointer += n; return true; } return false; }
		const uint8_t * data() const { return m_pointer; }
		size_t size() const { return m_buffer.end() - m_pointer; }
	private:
		const buffer	m_buffer;
		const uint8_t *	m_pointer;
	};

	template <typename T> inline oarchive& operator&(oarchive& oar, const T& t) { const_cast<T&>(t).serialize(oar); return oar; }
	inline oarchive& operator&(oarchive& oar, bool val) { if (!oar.write(val)) throw archive_error(); return oar; }
	inline oarchive& operator&(oarchive& oar, char val) { if (!oar.write(val)) throw archive_error(); return oar; }
	inline oarchive& operator&(oarchive& oar, int8_t val) { if (!oar.write(val)) throw archive_error(); return oar; }
	inline oarchive& operator&(oarchive& oar, int16_t val) { if (!oar.write(val)) throw archive_error(); return oar; }
	inline oarchive& operator&(oarchive& oar, int32_t val) { if (!oar.write(val)) throw archive_error(); return oar; }
	inline oarchive& operator&(oarchive& oar, int64_t val) { if (!oar.write(val)) throw archive_error(); return oar; }
	inline oarchive& operator&(oarchive& oar, uint8_t val) { if (!oar.write(val)) throw archive_error(); return oar; }
	inline oarchive& operator&(oarchive& oar, uint16_t val) { if (!oar.write(val)) throw archive_error(); return oar; }
	inline oarchive& operator&(oarchive& oar, uint32_t val) { if (!oar.write(val)) throw archive_error(); return oar; }
	inline oarchive& operator&(oarchive& oar, uint64_t val) { if (!oar.write(val)) throw archive_error(); return oar; }
	inline oarchive& operator&(oarchive& oar, float32_t val) { if (!oar.write(val)) throw archive_error(); return oar; }
	inline oarchive& operator&(oarchive& oar, float64_t val) { if (!oar.write(val)) throw archive_error(); return oar; }
	
	template <typename T> inline iarchive& operator&(iarchive& iar, T& t) { t.serialize(iar); return iar; }
	inline iarchive& operator&(iarchive& iar, bool & val) { if (!iar.read(val)) throw archive_error();return iar; }
	inline iarchive& operator&(iarchive& iar, char & val) { if (!iar.read(val)) throw archive_error();return iar; }
	inline iarchive& operator&(iarchive& iar, int8_t & val) { if (!iar.read(val)) throw archive_error();return iar; }
	inline iarchive& operator&(iarchive& iar, int16_t & val) { if (!iar.read(val)) throw archive_error(); return iar; }
	inline iarchive& operator&(iarchive& iar, int32_t & val) { if (!iar.read(val)) throw archive_error(); return iar; }
	inline iarchive& operator&(iarchive& iar, int64_t & val) { if (!iar.read(val)) throw archive_error(); return iar; }
	inline iarchive& operator&(iarchive& iar, uint8_t & val) { if (!iar.read(val)) throw archive_error(); return iar; }
	inline iarchive& operator&(iarchive& iar, uint16_t & val) { if (!iar.read(val)) throw archive_error(); return iar; }
	inline iarchive& operator&(iarchive& iar, uint32_t & val) { if (!iar.read(val)) throw archive_error(); return iar; }
	inline iarchive& operator&(iarchive& iar, uint64_t & val) { if (!iar.read(val)) throw archive_error(); return iar; }
	inline iarchive& operator&(iarchive& iar, float32_t & val) { if (!iar.read(val)) throw archive_error(); return iar; }
	inline iarchive& operator&(iarchive& iar, float64_t & val) { if (!iar.read(val)) throw archive_error(); return iar; }

	// array
	template <typename T, size_t Count>
	inline oarchive& operator&(oarchive& oar, const T(&arr)[Count])
	{
		oarchive::Mark m = oar.mark();
		try {
			oar.write_array(arr, Count);
		} catch (...) {
			oar.revert(m);
			throw archive_error();
		}
		return oar;
	}

	template <typename T, size_t Count>
	inline iarchive& operator&(iarchive& iar, T(&arr)[Count])
	{
		iarchive::Mark m = iar.mark();
		try {
			iar.read_array(arr, Count);
		} catch(...) {
			iar.revert(m);
			throw archive_error();
		}
		return iar;
	}

	// string
	template <typename T, typename R, typename A>
	inline oarchive& operator&(oarchive& oar, const base::basic_string<T, R, A> & val) 
	{
		oarchive::Mark m = oar.mark();
		size_t count = val.size();
		if (!oar.write_count_tag(count))
		{
			throw archive_error();
		}
		if (!oar.write((const void*)val.data(), count * sizeof(base::basic_string<T, R, A>::value_type)))
		{
			oar.revert(m);
			throw archive_error();
		}
		return oar;
	}

	template <typename T, typename R, typename A>
	inline iarchive& operator&(iarchive& iar, base::basic_string<T, R, A> & val) 
	{
		iarchive::Mark m = iar.mark();
		size_t count = 0;
		if (!iar.read_count_tag(count))
		{
			throw archive_error();
		}
		const uint8_t * p = iar.data();
		if (!iar.skip(count * sizeof(base::basic_string<T, R, A>::value_type)))
		{
			iar.revert(m);
			throw archive_error();
		}
		val.assign(base::basic_string<T, R, A>::const_pointer(p), count);
		return iar;
	}

	// list
	template <typename T, typename A>
	inline oarchive& operator&(oarchive& oar, const base::list<T, A> & val) 
	{
		oarchive::Mark m = oar.mark();
		size_t count = val.size();
		if (!oar.write_count_tag(count))
		{
			throw archive_error();
		}
		try {
			for (base::list<T, A>::const_iterator it = val.begin(); it != val.end(); ++it)
			{
				oar&(*it);
			}
		} catch(...) {
			oar.revert(m);
			throw archive_error();
		}
		return oar;
	}

	template <typename T, typename A>
	inline iarchive& operator&(iarchive& iar, base::list<T, A> & val) 
	{
		iarchive::Mark m = iar.mark();
		size_t count = 0;
		if (!iar.read_count_tag(count))
		{
			throw archive_error();
		}
		try {
			val.resize(count);
			for (base::list<T, A>::iterator it = val.begin(); it != val.end(); ++it)
			{
				iar&(*it);
			}
		} catch (...) {
			iar.revert(m);
			throw archive_error();
		}
		return iar;
	}

	//vector
	template <typename T, typename A>
	inline oarchive& operator&(oarchive& oar, const base::vector<T, A> & val) 
	{
		oarchive::Mark m = oar.mark();
		size_t count = val.size();
		if (!oar.write_count_tag(count))
		{
			throw archive_error();
		}
		try {
			for (base::vector<T, A>::const_iterator it = val.begin(); it != val.end(); ++it)
			{
				oar&(*it);
			}
		} catch(...) {
			oar.revert(m);
			throw archive_error();
		}
		return oar;
	}

	template <typename T, typename A>
	inline iarchive& operator&(iarchive& iar, base::vector<T, A> & val) 
	{
		iarchive::Mark m = iar.mark();
		size_t count = 0;
		if (!iar.read_count_tag(count))
		{
			throw archive_error();
		}
		try {
			val.resize(count);
			for (base::vector<T, A>::iterator it = val.begin(); it != val.end(); ++it)
			{
				iar&(*it);
			}
		} catch (...) {
			iar.revert(m);
			throw archive_error();
		}
		return iar;
	}

	//deque
	template <typename T, typename A>
	inline oarchive& operator&(oarchive& oar, const base::deque<T, A> & val) 
	{
		oarchive::Mark m = oar.mark();
		size_t count = val.size();
		if (!oar.write_count_tag(count))
		{
			throw archive_error();
		}
		try {
			for (base::deque<T, A>::const_iterator it = val.begin(); it != val.end(); ++it)
			{
				oar&(*it);
			}
		} catch(...) {
			oar.revert(m);
			throw archive_error();
		}
		return oar;
	}

	template <typename T, typename A>
	inline iarchive& operator&(iarchive& iar, base::deque<T, A> & val) 
	{
		iarchive::Mark m = iar.mark();
		size_t count = 0;
		if (!iar.read_count_tag(count))
		{
			throw archive_error();
		}
		try {
			val.resize(count);
			for (base::deque<T, A>::iterator it = val.begin(); it != val.end(); ++it)
			{
				iar&(*it);
			}
		} catch (...) {
			iar.revert(m);
			throw archive_error();
		}
		return iar;
	}

	//queue
	template <typename T, typename C>
	inline oarchive& operator&(oarchive& oar, const base::queue<T, C> & val) 
	{
		oarchive::Mark m = oar.mark();
		size_t count = val.size();
		if (!oar.write_count_tag(count))
		{
			throw archive_error();
		}
		try {
			for (base::queue<T, C>::const_iterator it = val.begin(); it != val.end(); ++it)
			{
				oar&(*it);
			}
		} catch(...) {
			oar.revert(m);
			throw archive_error();
		}
		return oar;
	}

	template <typename T, typename Container>
	inline iarchive& operator&(iarchive& iar, base::queue<T, Container> & val) 
	{
		iarchive::Mark m = iar.mark();
		size_t count = 0;
		if (!iar.read_count_tag(count))
		{
			throw archive_error();
		}
		try {
			val.resize(count);
			for (size_t i = 0; i < count; i++)
			{
				iar&(val[i]);
			}
		} catch (...) {
			iar.revert(m);
			throw archive_error();
		}
		return iar;
	}

	//set
	template <typename T, typename P, typename A>
	inline oarchive& operator&(oarchive& oar, const base::set<T, P, A> & val) 
	{
		oarchive::Mark m = oar.mark();
		size_t count = val.size();
		if (!oar.write_count_tag(count))
		{
			throw archive_error();
		}
		try {
			for (base::set<T, P, A>::const_iterator it = val.begin(); it != val.end(); ++it)
			{
				oar&(*it);
			}
		} catch(...) {
			oar.revert(m);
			throw archive_error();
		}
		return oar;
	}

	template <typename T, typename P, typename A>
	inline iarchive& operator&(iarchive& iar, base::set<T, P, A> & val) 
	{
		iarchive::Mark m = iar.mark();
		size_t count = 0;
		if (!iar.read_count_tag(count))
		{
			throw archive_error();
		}
		try {
			val.clear();
			T obj;
			for (size_t i = 0; i < count; i++)
			{
				iar&obj;
				val.insert(obj);
			}
		} catch (...) {
			iar.revert(m);
			throw archive_error();
		}
		return iar;
	}

	//multiset
	template <typename T, typename P, typename A>
	inline oarchive& operator&(oarchive& oar, const base::multiset<T, P, A> & val) 
	{
		oarchive::Mark m = oar.mark();
		size_t count = val.size();
		if (!oar.write_count_tag(count))
		{
			throw archive_error();
		}
		try {
			for (base::multiset<T, P, A>::const_iterator it = val.begin(); it != val.end(); ++it)
			{
				oar&(*it);
			}
		} catch(...) {
			oar.revert(m);
			throw archive_error();
		}
		return oar;
	}

	template <typename T, typename P, typename A>
	inline iarchive& operator&(iarchive& iar, base::multiset<T, P, A> & val) 
	{
		iarchive::Mark m = iar.mark();
		size_t count = 0;
		if (!iar.read_count_tag(count))
		{
			throw archive_error();
		}
		try {
			val.clear();
			T obj;
			for (size_t i = 0; i < count; i++)
			{
				iar&obj;
				val.insert(obj);
			}
		} catch (...) {
			iar.revert(m);
			throw archive_error();
		}
		return iar;
	}

	// map
	template <typename K, typename T, typename P, typename A>
	inline oarchive& operator&(oarchive& oar, const base::map<K, T, P, A> & val) 
	{
		oarchive::Mark m = oar.mark();
		size_t count = val.size();
		if (!oar.write_count_tag(count))
		{
			throw archive_error();
		}
		try {
			for (base::map<K, T, P, A>::const_iterator it = val.begin(); it != val.end(); ++it)
			{
				oar&(it->first)&(it->second);
			}
		} catch(...) {
			oar.revert(m);
			throw archive_error();
		}
		return oar;
	}

	template <typename K, typename T, typename P, typename A>
	inline iarchive& operator&(iarchive& iar, base::map<K, T, P, A> & val) 
	{
		iarchive::Mark m = iar.mark();
		size_t count = 0;
		if (!iar.read_count_tag(count))
		{
			throw archive_error();
		}
		try {
			val.clear();
			base::pair<K, T> vpair;
			for (size_t i = 0; i < count; i++)
			{
				iar&(vpair.first)&(vpair.second);
				val.insert(vpair);
			}
		} catch (...) {
			iar.revert(m);
			throw archive_error();
		}
		return iar;
	}

	// multimap
	template <typename K, typename T, typename P, typename A>
	inline oarchive& operator&(oarchive& oar, const base::multimap<K, T, P, A> & val) 
	{
		oarchive::Mark m = oar.mark();
		size_t count = val.size();
		if (!oar.write_count_tag(count))
		{
			throw archive_error();
		}
		try {
			for (base::multimap<K, T, P, A>::const_iterator it = val.begin(); it != val.end(); ++it)
			{
				oar&(it->first)&(it->second);
			}
		} catch(...) {
			oar.revert(m);
			throw archive_error();
		}
		return oar;
	}

	template <typename K, typename T, typename P, typename A>
	inline iarchive& operator&(iarchive& iar, base::multimap<K, T, P, A> & val) 
	{
		iarchive::Mark m = iar.mark();
		size_t count = 0;
		if (!iar.read_count_tag(count))
		{
			throw archive_error();
		}
		try {
			val.clear();
			base::pair<K, T> vpair;
			for (size_t i = 0; i < count; i++)
			{
				iar&(vpair.first)&(vpair.second);
				val.insert(vpair);
			}
		} catch (...) {
			iar.revert(m);
			throw archive_error();
		}
		return iar;
	}

	template <typename T> inline oarchive& operator<<(oarchive& oar, const T& t) { return oar&t; }
	template <typename T> inline iarchive& operator>>(iarchive& iar, T& t) { return iar&t; }
}

/// opt out for archive
namespace base
{
	// array

	// vector
	template <typename A>
	inline oarchive& operator&(oarchive& oar, const base::vector<bool, A> & val) 
	{
		oarchive::Mark m = oar.mark();
		size_t count = val.size();
		if (!oar.write_count_tag(count))
		{
			throw archive_error();
		}
		try {
			for (base::vector<bool, A>::const_iterator it = val.begin(); it != val.end(); ++it)
			{
				oar&(*it);
			}
		} catch(...) {
			oar.revert(m);
			throw archive_error();
		}
		return oar;
	}

	template <typename A>
	inline iarchive& operator&(iarchive& iar, base::vector<bool, A> & val) 
	{
		iarchive::Mark m = iar.mark();
		size_t count = 0;
		if (!iar.read_count_tag(count))
		{
			throw archive_error();
		}
		const uint8_t * p = iar.data();
		if (iar.skip(count))
		{
			try {
				val.assign((const bool*)p, (const bool*)iar.data());
			} catch (...) {
				iar.revert(m);
				throw archive_error();
			}
		}
		return iar;
	}
}
#endif

